
// <copyright file="ProcessPerfCounters.cs" company="Subhadra Software Solutions">
//   
// </copyright>
// <summary>
//   The process perf counters.
// </summary>

namespace SubhadraSolutions.Sharp.Utils.Diagnostics.Performance
{
    using System;
    using System.Diagnostics;

    /// <summary>
    /// The process perf counters.
    /// </summary>
    [PerfCounterCategory("Process Performance")]
    public sealed class ProcessPerfCounters : AbstractDisposable, IRefreshCounters
    {
        #region Static Fields

        /// <summary>
        /// The instance.
        /// </summary>
        private static readonly ProcessPerfCounters InstanceObject = new ProcessPerfCounters();

        #endregion Static Fields

        #region Fields

        /// <summary>
        /// The previous process cpu usage.
        /// </summary>
        private double _previousProcessCpuUsage;

        /// <summary>
        /// The previous system cpu usage.
        /// </summary>
        private float previousSystemCpuUsage;

        /// <summary>
        /// The previous thread count.
        /// </summary>
        private int previousThreadCount;

        /// <summary>
        /// The process cpu counter.
        /// </summary>
        private PerformanceCounter processCpuCounter;

        /// <summary>
        /// The system cpu counter.
        /// </summary>
        private PerformanceCounter systemCpuCounter;

        #endregion Fields

        // private CounterSample processCpuUsageStartSample;
        #region Constructors and Finalizers

        /// <summary>
        /// Prevents a default instance of the <see cref="ProcessPerfCounters"/> class from being created.
        /// </summary>
        private ProcessPerfCounters()
        {
            this.IsStarted = false;
        }

        #endregion Constructors and Finalizers

        #region Public Properties

        /// <summary>
        /// Gets the instance.
        /// </summary>
        public static ProcessPerfCounters Instance
        {
            get
            {
                return InstanceObject;
            }
        }

        /// <summary>
        /// Gets the base priority.
        /// </summary>
        [PerfCounter(GroupName = "Process Performance")]
        public int BasePriority
        {
            get
            {
                return ProcessHelper.CurrentProcess.BasePriority;
            }
        }

        /// <summary>
        /// Gets the handle count.
        /// </summary>
        [PerfCounter(GroupName = "Process Performance")]
        public int HandleCount
        {
            get
            {
                return ProcessHelper.CurrentProcess.HandleCount;
            }
        }

        /// <summary>
        /// Gets a value indicating whether is started.
        /// </summary>
        public bool IsStarted { get; private set; }

        /// <summary>
        /// Gets the paged memory size.
        /// </summary>
        [PerfCounter(GroupName = "Process Memory", SizeType = SizeTypes.Bytes, CounterSizeTypes = SizeTypes.MegaBytes)]
        public long PagedMemorySize
        {
            get
            {
                return ProcessHelper.CurrentProcess.PagedMemorySize64;
            }
        }

        /// <summary>
        /// Gets the paged system memory size.
        /// </summary>
        [PerfCounter(GroupName = "Process Memory", SizeType = SizeTypes.Bytes, CounterSizeTypes = SizeTypes.MegaBytes)]
        public long PagedSystemMemorySize
        {
            get
            {
                return ProcessHelper.CurrentProcess.PagedSystemMemorySize64;
            }
        }

        /// <summary>
        /// Gets the peak paged memory size.
        /// </summary>
        [PerfCounter(GroupName = "Process Memory", SizeType = SizeTypes.Bytes, CounterSizeTypes = SizeTypes.MegaBytes)]
        public long PeakPagedMemorySize
        {
            get
            {
                return ProcessHelper.CurrentProcess.PeakPagedMemorySize64;
            }
        }

        /// <summary>
        /// Gets the peak virtual memory size.
        /// </summary>
        [PerfCounter(GroupName = "Process Memory", SizeType = SizeTypes.Bytes, CounterSizeTypes = SizeTypes.MegaBytes)]
        public long PeakVirtualMemorySize
        {
            get
            {
                return ProcessHelper.CurrentProcess.PeakVirtualMemorySize64;
            }
        }

        /// <summary>
        /// Gets the peak working set.
        /// </summary>
        [PerfCounter(GroupName = "Process Memory", SizeType = SizeTypes.Bytes, CounterSizeTypes = SizeTypes.MegaBytes)]
        public long PeakWorkingSet
        {
            get
            {
                return ProcessHelper.CurrentProcess.PeakWorkingSet64;
            }
        }

        /// <summary>
        /// Gets the private memory size.
        /// </summary>
        [PerfCounter(GroupName = "Process Memory", SizeType = SizeTypes.Bytes, CounterSizeTypes = SizeTypes.MegaBytes)]
        public long PrivateMemorySize
        {
            get
            {
                return ProcessHelper.CurrentProcess.PrivateMemorySize64;
            }
        }

        /// <summary>
        /// Gets the privileged processor time.
        /// </summary>
        [PerfCounter(GroupName = "Process Performance", CounterTimeTypes = TimeTypes.Minutes)]
        public TimeSpan PrivilegedProcessorTime
        {
            get
            {
                return ProcessHelper.CurrentProcess.PrivilegedProcessorTime;
            }
        }

        /// <summary>
        /// Gets the process cpu usage.
        /// </summary>
        [PerfCounter(GroupName = "Process Performance")]
        public double ProcessCpuUsage
        {
            get
            {
                try
                {
                    if (this.processCpuCounter != null)
                    {
                        this._previousProcessCpuUsage = this.processCpuCounter.NextValue() / Environment.ProcessorCount;

                        // CounterSample curr = processCpuCounter.NextSample();

                        // double diffValue = (curr.RawValue - _processCpuUsageStartSample.RawValue) / Environment.ProcessorCount;
                        // double diffTimestamp = curr.TimeStamp100nSec - _processCpuUsageStartSample.TimeStamp100nSec;

                        // double usage = (diffValue / diffTimestamp) * 100;
                        // _previousProcessCpuUsage = usage;
                        // _processCpuUsageStartSample = processCpuCounter.NextSample();
                    }
                }
                catch (Exception ex)
                {
                    Debug.WriteLine(ex);
                }

                return this._previousProcessCpuUsage;
            }
        }

        /// <summary>
        /// Gets the system cpu usage.
        /// </summary>
        [PerfCounter(GroupName = "System Performance")]
        public float SystemCpuUsage
        {
            get
            {
                try
                {
                    if (this.systemCpuCounter != null)
                    {
                        this.previousSystemCpuUsage = this.systemCpuCounter.NextValue();
                    }
                }
                catch (Exception ex)
                {
                    Debug.WriteLine(ex);
                }

                return this.previousSystemCpuUsage;
            }
        }

        /// <summary>
        /// Gets the thread count.
        /// </summary>
        [PerfCounter(GroupName = "Process Performance")]
        public long ThreadCount
        {
            get
            {
                ProcessThreadCollection coll = ProcessHelper.CurrentProcess.Threads;
                this.previousThreadCount = coll.Count;
                return this.previousThreadCount;
            }
        }

        /// <summary>
        /// Gets the total processor time.
        /// </summary>
        [PerfCounter(GroupName = "Process Performance", CounterTimeTypes = TimeTypes.Minutes)]
        public TimeSpan TotalProcessorTime
        {
            get
            {
                return ProcessHelper.CurrentProcess.TotalProcessorTime;
            }
        }

        /// <summary>
        /// Gets the user processor time.
        /// </summary>
        [PerfCounter(GroupName = "Process Performance", CounterTimeTypes = TimeTypes.Minutes)]
        public TimeSpan UserProcessorTime
        {
            get
            {
                return ProcessHelper.CurrentProcess.UserProcessorTime;
            }
        }

        /// <summary>
        /// Gets the virtual memory size.
        /// </summary>
        [PerfCounter(GroupName = "Process Memory", SizeType = SizeTypes.Bytes, CounterSizeTypes = SizeTypes.MegaBytes)]
        public long VirtualMemorySize
        {
            get
            {
                return ProcessHelper.CurrentProcess.VirtualMemorySize64;
            }
        }

        /// <summary>
        /// Gets the working set.
        /// </summary>
        [PerfCounter(GroupName = "Process Memory", SizeType = SizeTypes.Bytes, CounterSizeTypes = SizeTypes.MegaBytes)]
        public long WorkingSet
        {
            get
            {
                return ProcessHelper.CurrentProcess.WorkingSet64;
            }
        }

        #endregion Public Properties

        #region Public Methods and Operators

        /// <summary>
        /// The refresh counters.
        /// </summary>
        public void RefreshCounters()
        {
            try
            {
                ProcessHelper.CurrentProcess.Refresh();
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex);
            }
        }

        /// <summary>
        /// The start.
        /// </summary>
        public void Start()
        {
            if (!this.IsStarted)
            {
                if (!GlobalSettings.Instance.IsService)
                {
                    try
                    {
                        this.systemCpuCounter = new PerformanceCounter("Processor", "% Processor Time", "_Total", true);
                    }
                    catch (Exception ex)
                    {
                        Debug.WriteLine(ex);
                    }

                    string currentProcessInstanceName = ProcessHelper.CurrentProcessInstanceName;
                    if (currentProcessInstanceName != null)
                    {
                        this.processCpuCounter = new PerformanceCounter("Process", "% Processor Time", currentProcessInstanceName, true);

                        // _processCpuUsageStartSample = processCpuCounter.NextSample();
                    }
                }

                this.IsStarted = true;
                PerfCounterManager.Instance.AddInstance(this, "Unique Instance", CounterStorageType.Memory);
            }
        }

        /// <summary>
        /// The stop.
        /// </summary>
        public void Stop()
        {
            if (this.IsStarted)
            {
                this.IsStarted = false;
                PerfCounterManager.Instance.RemoveInstance(this);
                if (this.systemCpuCounter != null)
                {
                    this.systemCpuCounter.Dispose();
                }

                if (this.processCpuCounter != null)
                {
                    this.processCpuCounter.Dispose();
                }
            }
        }

        #endregion Public Methods and Operators

        #region Methods

        /// <summary>
        /// The dispose.
        /// </summary>
        /// <param name="disposing">
        /// The disposing.
        /// </param>
        protected override void Dispose(bool disposing)
        {
            this.Stop();
        }

        #endregion Methods
    }
}